/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "M2SkeletonLoadImpl.h"

#include "Logger.h"

namespace PQGameCore
{
	M2SkeletonLoadImpl::M2SkeletonLoadImpl(Ogre::Skeleton *skeleton)
		: _skeleton(skeleton)
	{
		assert(_skeleton);
	}

	void M2SkeletonLoadImpl::load(std::string path)//m2 path
	{
		_path=path;
		_m2Model=M2Model::get(path);
		_m2File=_m2Model->getM2File();
		_animFileList=_m2Model->getAnimFiles();
		_boneCount=_m2File->getBoneCount();
		_m2Bones= _m2File->getBonePtr();//bones in m2 file
		_animCount=_m2File->getAnimCount();
		_m2Anims= _m2File->getAnimsPtr();
		_globalSeqs=_m2File->getGlobSeqPtr();
		

		initM2Bones();
		
		initM2Animations();
	}

	void M2SkeletonLoadImpl::initM2Bones()
	{
		for (int i=0; i<_boneCount; i++) {
			Ogre::Bone* bone=_skeleton->createBone();
			_boneList.push_back(bone);
			_m2Model->addBoneHandle(bone->getHandle());
			
		}

		for (int i=0; i<_boneCount; i++) {
			initBoneTree(i);//build bone tree
		}

	}

	void M2SkeletonLoadImpl::initM2Bone(int index)
	{
		M2Bone* b=_m2Bones+index;
		Ogre::Vector3 pivot = fixCoord(Ogre::Vector3(b->pivot));
		Ogre::Bone *bone= _boneList[index];
		bone->setPosition(pivot);
		bone->setOrientation(Ogre::Quaternion());//??
		bone->setScale(Ogre::Vector3::UNIT_SCALE);
		bone->setInitialState();

		//PQGameCore.createSphereObject(pivot);

		_m2Model->addBoneHandle(bone->getHandle());
	}

	void M2SkeletonLoadImpl::initBoneTree(int index)
	{
		M2Bone* b=_m2Bones+index;
		Ogre::Vector3 pivot = fixCoord(Ogre::Vector3(b->pivot));
		Ogre::Bone* bone=_boneList[index];
		
		int id=b->parent;
		if(id!=-1){
			if(id<0||id>=_boneList.size()){
				GNgLog.out("Can't fine parent bone...");
			}
			_boneList[id]->addChild(bone);
			bone->_setDerivedPosition(pivot);
			bone->setInitialState();
			
		}else{
			bone->setPosition(pivot);
			bone->setInitialState();
			GNgLog.out("Root bone...");
		}

	}

	void M2SkeletonLoadImpl::initM2Animations()
	{
		int size=_m2Model->getAnimCount();
		for(int i=0;i<size;i++){
			Ogre::String animName=_m2Model->getAnimName(i);
			if(animName.empty()){
				continue;
			}
			if(animName=="Run[2]"){//only for test run human model
			//if(animName=="
				unsigned int len=_m2Model->getAnimLength(i);
				float secs=(float)len/1000.0f;
				Ogre::Animation *anim=0;
				if(!_skeleton->hasAnimation(animName)){
					anim= _skeleton->createAnimation(animName, secs);
				}else{
					anim= _skeleton->getAnimation(animName);
				}
				for(int b=0;b<_boneCount;b++){
					initBoneAnim(anim,i,b);
					
				}
			}
		}
	}

	//very mem time waste??BUG
	void M2SkeletonLoadImpl::initBoneAnim(Ogre::Animation* anim,int animIndex,int boneIndex)
	{
		M2Bone* b=_m2Bones+boneIndex;
		Ogre::Vector3 pivot = fixCoord(Ogre::Vector3(b->pivot));

		//anim->setInterpolationMode(Ogre::Animation::IM_LINEAR);
		Ogre::Bone* bone=_boneList[boneIndex];
		Ogre::NodeAnimationTrack *nat=0;
		if(anim->hasNodeTrack(bone->getHandle())){
			nat=anim->getNodeTrack(bone->getHandle());
		}else{
			nat=anim->createNodeTrack(bone->getHandle(),bone);
		}

		Ogre::Real len= anim->getLength();
		float fps=10.f;//
		float dt=len/fps;

		bool hasTr=false;
		bool hasRt=false;
		bool hasSc=false;
		M2AnimData* dtTr= _m2Model->getBoneTranslateData(boneIndex);
		M2AnimData* dtRt= _m2Model->getBoneRotateData(boneIndex);
		M2AnimData* dtSc= _m2Model->getBoneScaleData(boneIndex);
		if(dtTr&&dtTr->hasAnimData(animIndex)){
			hasTr=true;
		}
		if(dtRt&&dtRt->hasAnimData(animIndex)){
			hasRt=true;
		}
		if(dtSc&&dtSc->hasAnimData(animIndex)){
			hasSc=true;
		}
		
		for(float time=dt;time<len;time+=dt){
			/// add a new time key
			Ogre::TransformKeyFrame *tkf=nat->createNodeKeyFrame(time);
			if(hasTr){
				Ogre::Vector3 trans=fixCoord(dtTr->getVector3(animIndex,time*1000));
				tkf->setTranslate(trans);
			}


			if(hasRt){
				//Ogre::Vector4 vec=fixCoordVec4(dtRt->getUnpackVector4(animIndex,time*1000));
				//Ogre::Quaternion q(vec.w,vec.x,vec.y,vec.z);
				//tkf->setRotation(q);
			}
				
			//if(hasSc){
				//Ogre::Vector3 scale=fixCoord(dtSc->getVector3(animIndex,time));
				//tkf->setScale(scale);
			//}

		}
		
	}

	
}

